class: center, middle, inverse, title-slide .title[ # Hands-on Exercise 7: Handling and Visualising Geospatial Data with R ] .author[ ### Dr. Kam Tin Seong
Assoc. Professor of Information Systems ] .institute[ ### School of Computing and Information Systems,
Singapore Management University ] .date[ <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html ### 2020-2-15 (updated: 2022-05-21) ======= ### 2020-2-15 (updated: 2022-05-16) >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html ] --- ## Content .large[ - Mapping Geospatial Point Data with R - Choropleth Mapping with R ] --- ## Ex 1:Mapping Geospatial Point Data with R .pull-left[ In this hands-on exercise, you will learn how to create proportional symbol map by using **tmap** package. - By the end of this hands-on exercise, you will be able: - to import an aspatial data in R by using **readr** pakage, - to convert it into simple point feature by using **sf** package, and - to create interactive proportional symbol maps by using **tmap** package. ] --- ## Getting Started .pull-left[ Write a code chunk to check, install and launch **readr**, **sf** and **tmap** packages of R] -- .pull-right[ The solution: ] --- ## Importing wkt data .pull-left[ - *Well-known text (WKT)* is a human readable representation for spatial objects like points, lines, or enclosed areas on a map. ] -- .pull-right[ <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html ```r sgpools_sf <- st_as_sf( sgpools, * coords = c("XCOORD", * "YCOORD"), * crs= 3414) ``` ] --- ## Ploting a point symbol map .pull-left[ .small[ The code chunk below is used to create an interactive point symbol map. ```r tmap_mode("view") tm_shape(sgpools_sf)+ tm_bubbles(col = "red", size = 1, border.col = "black", border.lwd = 1) ``` Things to learn from the code chunk: - `tmap_mode()` is used to switch the display from static mode (i.e. "plot") to interactive mode (i.e. "view"). - `tm_shape()` is used to create a **tmap-element** that specifies a spatial data object (i.e. point). - `tm_bubble()` is used to create a **tmap-element** that draws bubbles or small dots. Both colors and sizes of the bubbles can be mapped to data variables. ]] .pull-right[
] --- ## Lets make it proportional .pull-left[ To draw a proportional symbol map, we need to assign a numerical variable to the size visual attribute. The code chunks below show that the variable *Gp1Gp2Winnings* is assigned to size visual attribute. ======= The solution: >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html ```r schools <- read_sf("data/wkt/Schools.csv", options = "GEOM_POSSIBLE_NAMES=location") ``` <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html ] .pull-right[
] ======= >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html DIY: ```r pubs <- read_sf("data/wkt/Pubs.csv", options = "GEOM_POSSIBLE_NAMES=location") apartments <- read_sf("data/wkt/Apartments.csv", options = "GEOM_POSSIBLE_NAMES=location") buildings <- read_sf("data/wkt/Buildings.csv", options = "GEOM_POSSIBLE_NAMES=location") employers <- read_sf("data/wkt/Employers.csv", options = "GEOM_POSSIBLE_NAMES=location") restaurants <- read_sf("data/wkt/Restaurants.csv", options = "GEOM_POSSIBLE_NAMES=location") ``` <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html
======= >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html - After importing the data file into R, it is important for us to review the data object. ] --- ```r bldgs <- read_sf("data/wkt/Buildings.csv", options = "GEOM_POSSIBLE_NAMES=location") ``` --- ```r print(schools) ``` ``` ## Simple feature collection with 4 features and 4 fields ## Geometry type: POINT ## Dimension: XY ## Bounding box: xmin: -4701.463 ymin: 1607.984 xmax: -376.7505 ymax: 6556.032 ## CRS: NA ## # A tibble: 4 × 5 ## schoolId monthlyCost maxEnrollment location buildingId ## <chr> <chr> <chr> <POINT> <chr> ## 1 0 12.81244502 242 (-376.7505 1607.984) 662 ## 2 450 91.14351385 418 (-2597.448 3194.155) 943 ## 3 900 38.00537955 394 (-2539.158 6556.032) 262 ## 4 1350 73.19785215 384 (-4701.463 5141.763) 123 ``` --- <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html Next, we will import *respopagsex2000to2018.csv* file into RStudio and save the file into an R dataframe called *popagsex*. The task will be performed by using `read_csv()` function of **readr** package as shown in the code chunk below. ```r popagsex <- read_csv("data/aspatial/respopagsex2000to2018.csv") ``` --- ## Data Preparation .pull-left[ Before a thematic map can be prepared, you need to preform the following data preparation. - Extracting 2018 records only. - Extracting Males records only. - Deriving three new variables, namely: Young, Economic Active and Aged. The following data wrangling and transformation functions will be used: - `spread()` of **tidyr** package, and - `mutate()`, `filter()`, and `select()` of **dplyr** package ] .pull-right[ The code chunk: ```r popagsex2018_male <- popagsex %>% filter(Sex == "Males") %>% filter(Time == 2018) %>% spread(AG, Pop) %>% mutate(YOUNG = `0_to_4`+`5_to_9`+`10_to_14`+ `15_to_19`+`20_to_24`) %>% mutate(`ECONOMY ACTIVE` = rowSums(.[9:13])+ rowSums(.[15:17]))%>% mutate(`AGED`=rowSums(.[18:22])) %>% mutate(`TOTAL`=rowSums(.[5:22])) %>% mutate(`DEPENDENCY` = (`YOUNG` + `AGED`) /`ECONOMY ACTIVE`) %>% mutate_at(.vars = vars(PA, SZ), .funs = funs(toupper)) %>% select(`PA`, `SZ`, `YOUNG`, `ECONOMY ACTIVE`, `AGED`, `TOTAL`, `DEPENDENCY`) %>% filter(`ECONOMY ACTIVE` > 0) ``` ] --- ### Joining the attribute data and geospatial data .large[ Next, `left_join()` of **dplyr** is used to join the geographical data and attribute table using planning subzone name e.g. *SUBZONE_N* and *SZ* as the common identifier. ```r mpsz_agemale2018 <- left_join(mpsz, popagsex2018_male, by = c("SUBZONE_N" = "SZ")) ``` ] --- ## Plotting a choropleth map quickly by using *qtm()* .pull-left[ The easiest and quickest to draw a choropleth map using **tmap** is using `qtm()`. It is concise and provides a good default visualisation in many cases. The code chunk below will draw a cartographic standard choropleth map as shown below. ```r tmap_mode("plot") qtm(mpsz_agemale2018, fill = "DEPENDENCY") ``` Things to learn from the code chunk above: - `tmap_mode()` with "plot" option is used to produce a static map. - `fill` argument is used to map the attribute (i.e. DEPENDENCY) ] .pull-right[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-16-1.png" width="504" /> ] --- ## Drawing a base map .pull-left[ The basic building block of **tmap** is `tm_shape()` followed by one or more layer elemments such as `tm_fill()` and `tm_polygons()`. In the code chunk below, `tm_shape()` is used to define the input data (i.e *mpsz_agmale2018*) and `tm_polygons()` is used draw the planning subzone polygons ```r tm_shape(mpsz_agemale2018) + tm_polygons() ``` .blue[ Be warned: The "+" sign should be place at the end of a code line and not at the front of a code line. ] ] .pull-right[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-18-1.png" width="504" /> ] --- ## Drawing a choropleth map using `tm_polygons()` .pull-left[ To draw a choropleth map showing the geographical distribution of a selected variable by planning subzone, we just need to assign the target variable such as *DEPENDENCY* to `tm_polygons()`. ======= >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html ```r print(buildings) ``` <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html Things to learn from `tm_polygons()`: - By default, 5 bins will be used. - The default data classification method used is called "pretty". - The default colour scheme used is "YlOrRd" of ColorBrewer. You will learn more about the color palette later. - By default, Missing value will be shaded in gray. ] .pull-right[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-20-1.png" width="504" /> ] --- ### Drawing a choropleth map using `tm_fill()` and `tm_border()` .pull-left[ Actually, `tm_polygons()` is a wrapper of `tm_fill()` and `tm_border()`. `tm_fill()` shades the polygons by using the default colour scheme and `tm_borders()` adds the borders of the shapefile onto the choropleth map. The code chunk below draw a choropleth map by using `tm_fill()` alone. ```r tm_shape(mpsz_agemale2018)+ * tm_fill("DEPENDENCY") ``` Notice that the planning subzones are shared according to the respective dependecy values ] .pull-right[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-22-1.png" width="504" /> ] --- ### Drawing a choropleth map using `tm_border()` .pull-left[ To add the boundary of the planning subzones, `tm_border()` will be used as shown in the code chunk below. ```r tm_shape(mpsz_agemale2018)+ tm_fill("DEPENDENCY") + * tm_borders(lwd = 0.1, * alpha = 1) ``` Notice that light-gray border lines have been added on the choropleth map. - *lwd* = border line width. The default is 1, - *alpha* = transparency number between 0 (totally transparent) and 1 (not transparent). By default, the alpha value of the col is used (normally 1), - *col* = border colour, and - *lty* = border line type. The default is "solid". ] .pull-right[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-24-1.png" width="504" /> ] --- ## Data classification methods of **tmap** .pull-left[ Most choropleth maps employ some method of data classification. The point of classification is to take a large number of observations and group them into data ranges or classes. **tmap** provides a total ten data classification methods, namely: *fixed*, *sd*, *equal*, *pretty* (default), *quantile*, *kmeans*, *hclust*, *bclust*, *fisher*, and *jenks*. To define a data classification method, the `style` argument of `tm_fill()` or `tm_polygons()` will be used. The code chunk below shows a quantile data classification with 8 classes are used. ```r tm_shape(mpsz_agemale2018)+ tm_fill("DEPENDENCY", * n = 8, * style = "quantile") + tm_borders(alpha = 0.5) ======= ``` ## Simple feature collection with 1042 features and 4 fields ## Geometry type: POLYGON ## Dimension: XY ## Bounding box: xmin: -4762.191 ymin: -30.08359 xmax: 2650 ymax: 7850.037 ## CRS: NA ## # A tibble: 1,042 × 5 ## buildingId location buildingType maxOccupancy units ## <chr> <POLYGON> <chr> <chr> <chr> ## 1 1 ((350.0639 4595.666, 390.0633 459… Commercial "" "" ## 2 2 ((-1926.973 2725.611, -1948.191 2… Residental "12" "[48… ## 3 3 ((685.6846 1552.131, 645.9985 154… Commercial "" "[38… ## 4 4 ((-976.7845 4542.382, -1053.288 4… Commercial "" "" ## 5 5 ((1259.306 3572.727, 1299.255 357… Residental "2" "[23… ## 6 6 ((478.8969 1082.484, 473.6596 113… Commercial "" "" ## 7 7 ((-1920.823 615.7447, -1960.818 6… Residental "" "" ## 8 8 ((-3302.657 5394.354, -3301.512 5… Commercial "" "[13… ## 9 9 ((-600.5789 4429.228, -495.9506 4… Commercial "" "" ## 10 10 ((-68.75908 5379.924, -28.78232 5… Residental "5" "[10… ## # … with 1,032 more rows >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html ``` <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html .pull-right[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-26-1.png" width="504" /> ] --- ### Comparing Quantile and Equal Interval In the code chunk below, *quantile* and *equal* data classification methods are used. Notice that the distribution of quantile data classification method are more evenly distributed then equal data classification method. .pull-left[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-27-1.png" width="504" /> ] .pull-right[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-28-1.png" width="504" /> ] --- ## Colour Scheme ======= --- ## Ploting a point symbol map >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html .pull-left[ The code chunk below is used to create an interactive point symbol map. ```r tmap_mode("view") tm_shape(buildings)+ tm_polygons(col = "grey60", size = 1, border.col = "black", border.lwd = 1) ``` <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html Notice that the choropleth map is shaded in blue. ] .pull-right[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-30-1.png" width="504" /> ] --- ### More about colour .pull-left[ To reverse the colour shading, add a "-" prefix. ======= Things to learn from the code chunk: - `tmap_mode()` is used to switch the display from static mode (i.e. "plot") to interactive mode (i.e. "view"). >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html - `tm_shape()` is used to create a **tmap-element** that specifies a spatial data object (i.e. point). - `tm_bubble()` is used to create a **tmap-element** that draws bubbles or small dots. Both colors and sizes of the bubbles can be mapped to data variables. ]] .pull-right[ <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-32-1.png" width="504" /> ] --- ## Map Layouts Map layout refers to the combination of all map elements into a cohensive map. Map elements include among others the objects to be mapped, the title, the scale bar, the compass, margins and aspects ratios, while the colour settings and data classification methods covered in the previous section relate to the palette and break-points used to affect how the map looks. --- ### Map Legend In **tmap**, several *legend* options are provided to change the placement, format and appearance of the legend. ```r tm_shape(mpsz_agemale2018)+ tm_fill("DEPENDENCY", style = "quantile", palette = "Blues", legend.hist = TRUE, legend.is.portrait = TRUE, legend.hist.z = 0.1) + * tm_layout(main.title = "Distribution of Dependency Ratio by planning subzone \n(Quantile classification)", * main.title.position = "center", * main.title.size = 1, * legend.height = 0.45, * legend.width = 0.35, * legend.outside = FALSE, * legend.position = c("right", "bottom"), * frame = FALSE) + tm_borders(alpha = 0.5) ``` --- ### Map Legend The output map <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-34-1.png" width="864" /> --- ### Map style .pull-left[ **tmap** allows a wide variety of layout settings to be changed. They can be called by using `tmap_style()`. ======= >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html
] <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html .pull-right[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-36-1.png" width="504" /> ] --- ## Cartographic Furniture Beside map style, **tmap** also also provides arguments to draw other map furniture such as compass, scale bar and grid lines. In the code chunk below, `tm_compass()`, `tm_scale_bar()` and `tm_grid()` are used to add compass, scale bar and grid lines onto the choropleth map. ```r tm_shape(mpsz_agemale2018)+ tm_fill("DEPENDENCY", style = "quantile", palette = "Blues", title = "No. of persons") + tm_layout(main.title = "Distribution of Dependency Ratio \nby planning subzone", main.title.position = "center", main.title.size = 1.2, legend.height = 0.45, legend.width = 0.35, frame = TRUE) + * tm_borders(alpha = 0.5) + * tm_compass(type="8star", size = 2) + * tm_scale_bar(width = 0.15) + * tm_grid(lwd = 0.1, alpha = 0.2) + * tm_credits("Source: Planning Sub-zone boundary from Urban Redevelopment Authorithy (URA)\n and Population data from Department of Statistics DOS", * position = c("left", "bottom")) ``` To reset the default style, the code chunk use the code chunk below. ```r tmap_style("white") ``` --- ## Cartographic Furniture The output plot <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-39-1.png" width="864" /> To reset back to the default style, the code chunk below should be used.. ```r tmap_style("white") ``` ======= >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html --- ## Ploting a point symbol map .pull-left[ The code chunk below is used to create an interactive point symbol map. ```r tmap_mode("view") tm_shape(buildings)+ tm_polygons(col = "grey60", size = 1, border.col = "black", border.lwd = 1) + tm_shape(employers) + tm_dots(col = "red") ``` ] .pull-right[ <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-42-1.png" width="504" /> ] --- ### By assigning multiple values to at least one of the aesthetic arguments .pull-left[ In this example, small multiple choropleth maps are created by assigning multiple values to at least one of the aesthetic arguments ```r tm_shape(mpsz_agemale2018)+ * tm_polygons(c("DEPENDENCY","AGED"), * style = c("equal", "quantile"), * palette = list("Blues","Greens")) + tm_layout(legend.position = c("right", "bottom")) ``` ] .pull-right[ <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-44-1.png" width="504" /> =======
>>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html ] --- ## Ploting a composite point symbol map .pull-left[ The code chunk below is used to create an interactive point symbol map. ```r tmap_mode("view") tm_shape(buildings)+ tm_polygons(col = "grey60", size = 1, border.col = "black", border.lwd = 1) + tm_shape(employers) + tm_dots(col = "red") + tm_shape(apartments) + tm_dots(col = "lightblue") + tm_shape(pubs) + tm_dots(col = "green") + tm_shape(restaurants) + tm_dots(col = "blue") + tm_shape(schools) + tm_dots(col = "yellow") ``` ] .pull-right[ <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-46-1.png" width="504" /> ] --- ### By creating multiple stand-alone maps with `tmap_arrange()` ======= >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html
] <<<<<<< HEAD:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07-BasicMapping.html --- ### By creating multiple stand-alone maps with `tmap_arrange()` .large[ The output choropleth maps] <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-48-1.png" width="1080" /> --- ## Mappping Spatial Object Meeting a Selection Criterion .large[ Instead of creating small multiple choropleth map, you can also use selection function to map spatial objects meeting the selection criterion. ```r *tm_shape(mpsz_agemale2018[mpsz_agemale2018$REGION_N=="CENTRAL REGION", ]) + tm_fill("DEPENDENCY", style = "quantile", palette = "Blues", legend.hist = TRUE, legend.is.portrait = TRUE, legend.hist.z = 0.1) + tm_layout(legend.outside = TRUE, legend.height = 0.45, legend.width = 5.0, legend.position = c("right", "bottom"), frame = FALSE) + tm_borders(alpha = 0.5) ``` --- ## Mappping Spatial Object Meeting a Selection Criterion The output choropleth maps. <img src="Hands-on_Ex07-BasicMapping_files/figure-html/unnamed-chunk-50-1.png" width="864" /> ======= >>>>>>> 0289d5edd0906576c9939423d0beef18ebf55060:Hands-on_Ex/Hands-on_Ex07/Hands-on_Ex07.html